import logging

from _testcapi import raise_exception
from django.shortcuts import render

# Create your views here.
from rest_framework.decorators import action
from rest_framework.mixins import ListModelMixin, CreateModelMixin
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.status import HTTP_400_BAD_REQUEST, HTTP_500_INTERNAL_SERVER_ERROR, HTTP_201_CREATED, \
    HTTP_404_NOT_FOUND
from rest_framework.viewsets import GenericViewSet, ModelViewSet, ReadOnlyModelViewSet

from DrfStudy_33.settings import alipay
from celery_tasks.email.tasks import send_mail_task
from shopping.models import *
from shopping.serializers import *


class ClassificationViewSet(GenericViewSet, ListModelMixin):
    queryset = Classification.objects.filter(is_delete=False)
    serializer_class = ClassificationSerializer
    permission_classes = [IsAuthenticated]

    # 重写数据查询集
    def get_queryset(self):
        if self.action == 'list':
            return self.queryset.filter(parent__isnull=True)
        return self.queryset

    # 重新获取序列化器类
    def get_serializer_class(self):
        if self.action == 'list':
            return ParentClassificationSerializer
        return self.serializer_class

    @action(methods=['get'], detail=True)
    def commodity(self, request, pk):
        # 获取指定分类下的所有的商品
        # 获取一级分类下的所有商品 数码产品下的所有的商品
        # 获取二级分类下的所有的商品 手机分类下的所有的商品
        # 校验商品分类的id是否正确
        try:
            classification = self.get_queryset().get(id=pk)
        except Classification.DoesNotExist:
            return Response(status=HTTP_400_BAD_REQUEST)
        # 默认为一级分类
        classification_attr = 'classification1'
        classification_name = classification.name  # 获取分类的名字
        if classification.parent:
            classification_attr = 'classification2'
            # 二级分类名 获取到的名字拼接他的一级分类 父类商品分类
            classification_name = f'{classification.parent.name}-{classification.name}'
        # 通过分类找到对应的商品数据
        # . 点并不会解析变量保存的值 直接把变量名当做属性名来获取
        # classification.classification_attr.filter(is_delete=False,status=1)
        # 获取该对象的属性值
        data = getattr(classification, classification_attr).filter(is_delete=False, status=1)
        return Response(
            {'classification': classification_name,
             'commodity': CommoditySerializer(data, many=True).data
             }
        )


logger = logging.getLogger(__name__)


class CommodityViewSet(ModelViewSet):
    queryset = Commodity.objects.filter(is_delete=False)
    serializer_class = CommoditySerializer
    permission_classes = [IsAuthenticated]

    def create(self, request, *args, **kwargs):
        # 获取用户传入的数据 并校验
        # 验证商品基本信息 并保存
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)  # 如果商品信息有误 直接返回错误
        # 保存商品 获取商品实例
        commodity = serializer.save()
        # 处理图片上传
        # 获取用户传入的商品图片 可以传入多张图片
        files = request.FILES.getlist('file')  # 得到file字段上传的所有图片文件放到列表里面
        max_size = 5 * 1024 * 1024  # 5mb
        # 获取每张图片验证文件类型和大小
        for file in files:
            # try:
            if file.content_type not in ("image/jpeg", "image/png"):
                print(file.content_type)
                return Response(
                    {"error": "仅支持jpg png格式图片"},
                    status=HTTP_400_BAD_REQUEST
                )
            if file.size > max_size:
                return Response(
                    {"error": "图片大小不能超过5MB"},
                    status=HTTP_400_BAD_REQUEST
                )
                # 保存商品图片到模型

            CommodityImg.objects.create(
                src=file,  # 关键保存图片
                commodity=commodity,  # 关联商品信息
                priority=0,
                # 根据需求设置优先级
            )
            # except Exception as e:
            #     #  如果商品图片保存失败 手动回滚商品创建（避免只有商品没有图片）
            #     commodity.delete()
            #     logger.error(f'商品图片保存失败：{str(e)}')
            #     return Response(
            #         {"error": "图片上传失败，请重试"},
            #         status=HTTP_500_INTERNAL_SERVER_ERROR
            #     )
        # 返回序列化后的商品信息 包含图片
        return Response(self.get_serializer(commodity).data, status=HTTP_201_CREATED)

    @action(methods=['get'], detail=False)
    def optimization(self, request):
        queryset = self.get_queryset().order_by('-comments', '-create_time')
        # 切片得到前五个
        queryset = queryset[:5] if len(queryset) > 5 else queryset
        return Response(self.get_serializer(queryset, many=True).data)


class ShoppingCartViewSet(ModelViewSet):
    queryset = ShoppingCart.objects.all()
    serializer_class = ShoppingCartSerializer
    permission_classes = [IsAuthenticated]

    # 限制添加购物车商品只能为当前登录的用户
    def create(self, request, *args, **kwargs):
        request.POST._mutable = True
        request.data["user"] = request.user.id
        return ModelViewSet.create(self, request, *args, **kwargs)

    # 限制只能查看当前登录的这个用户购物车商品
    def get_queryset(self):
        return self.request.user.shoppingcart_set.all()


class OrderViewSet(ReadOnlyModelViewSet, CreateModelMixin):
    queryset = Order.objects.all()
    serializer_class = OrderSerializer
    permission_classes = [IsAuthenticated]

    def get_queryset(self):
        return self.request.user.order_set.all()

    @action(methods=['put'], detail=False)
    def status(self, request):
        # 得到支付宝回调传过来的数据，在请求地址里面
        query_dict = request.query_params  # 得到的地址栏参数
        data = query_dict.dict()

        # 得到订单编号 支付宝交易号
        order_id = data.get('out_trade_no')
        trade_no = data.get('trade_no')
        with transaction.atomic():
            save_point = transaction.savepoint()
            try:
                Payment.objects.create(
                    order_id=order_id,
                    trade_id=trade_no
                )
                self.get_queryset().filter(order_id=order_id, status=1).update(status=2)
            except Exception as e:
                transaction.savepoint_rollback(save_point)
                return Response(status=HTTP_500_INTERNAL_SERVER_ERROR)
            else:
                transaction.savepoint_commit(save_point)
                # 发送邮件的内容 得到该订单中的每个商品的信息
                for i in self.queryset.get(order_id=order_id).ordergoods_set.all():
                    send_mail_task.delay(
                        i.order.users.email,
                        f"""
                        <h2>下单成功</h2>
                        <h3>您在HAOKE商城购买的[{i.community.name}*{i.numbers}]下单成功，待发货中</h3>
                        """
                    )
            return Response({'order_id': order_id, 'trade_id': trade_no})


class PaymentViewSet(ReadOnlyModelViewSet):
    queryset = Payment.objects.all()
    serializer_class = PaymentSerializer

    @action(methods=['get'], detail=True)
    def pay(self, request, pk):
        # 得到支付宝的待支付页面 客户端跳转到支付宝的待支付页面 让用户进行支付的操作
        try:
            # 获取对应的订单信息，并且订单的所有者应该是当前登录的用户，需要是待支付的状态
            order = Order.objects.get(order_id=pk, users=request.user, status=1)
        except Order.DoesNotExist:
            return Response(status=HTTP_404_NOT_FOUND)
        # 调用支付宝的接口
        order_string = alipay.api_alipay_trade_page_pay(
            #     得到订单号
            out_trade_no=order.order_id,
            #     支付金额
            total_amount=str(order.total_amount),
            #     标题
            subject=f'HAOKE平台{order.order_id}',
            #     回调地址 支付成功了让支付宝去到那个页面
            # 前端的支付结果页面
            return_url='http://localhost:5173/order/success'
        )
        # 支付宝网关地址
        pay_url = "https://openapi-sandbox.dl.alipaydev.com/gateway.do?" + order_string
        return Response({'pay_url': pay_url})
